Skip to content

Add Node.js integration: package, tests, and CI#4

Merged
sinkingsugar merged 1 commit into
pure-c-portfrom
claude/node-integration-options-Is824
Apr 12, 2026
Merged

Add Node.js integration: package, tests, and CI#4
sinkingsugar merged 1 commit into
pure-c-portfrom
claude/node-integration-options-Is824

Conversation

@sinkingsugar

Copy link
Copy Markdown
Member

Ship an npm package that exports the path to the cr-sqlite loadable extension for use with node:sqlite (Node >= 22.5) or better-sqlite3.

  • Add package.json with ESM + CJS dual exports
  • Rewrite nodejs-helper.js with usage docs, add nodejs-helper.cjs
  • Add 12 integration tests covering extension loading, CRR operations, merge/sync between databases, and last-write-wins conflict resolution
  • Add GitHub Actions workflow (node-tests.yaml) running on ubuntu + macOS
  • Remove stale nodejs-install-helper.js and pnpm-lock.yaml (referenced deleted package.json and old vlcn-io release URLs)

https://claude.ai/code/session_0156tM6LmjAC3xYz5xwETvym

Ship an npm package that exports the path to the cr-sqlite loadable
extension for use with node:sqlite (Node >= 22.5) or better-sqlite3.

- Add package.json with ESM + CJS dual exports
- Rewrite nodejs-helper.js with usage docs, add nodejs-helper.cjs
- Add 12 integration tests covering extension loading, CRR operations,
  merge/sync between databases, and last-write-wins conflict resolution
- Add GitHub Actions workflow (node-tests.yaml) running on ubuntu + macOS
- Remove stale nodejs-install-helper.js and pnpm-lock.yaml (referenced
  deleted package.json and old vlcn-io release URLs)

https://claude.ai/code/session_0156tM6LmjAC3xYz5xwETvym
Copilot AI review requested due to automatic review settings April 11, 2026 22:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a Node.js integration surface for cr-sqlite by introducing an npm package (dual ESM/CJS) that exposes the loadable extension path, along with Node-based integration tests and a GitHub Actions workflow to run them.

Changes:

  • Added core/package.json and Node helper entrypoints (nodejs-helper.js / nodejs-helper.cjs + typings) to ship an npm package exporting the extension path.
  • Added Node integration tests (core/test/integration.test.mjs) covering extension loading and replication/merge behaviors.
  • Added CI workflow (.github/workflows/node-tests.yaml) to build the extension and run Node integration tests on ubuntu/macOS; removed stale Node install helper and pnpm lockfile.

Reviewed changes

Copilot reviewed 6 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
core/test/integration.test.mjs Adds Node node:test integration coverage for extension loading, CRR operations, and merge/sync scenarios.
core/package.json Defines the npm package metadata, dual exports (ESM/CJS), build/test scripts, and engine requirement.
core/nodejs-helper.js ESM helper exporting extensionPath with usage docs for node:sqlite and better-sqlite3.
core/nodejs-helper.cjs CJS entry point exporting extensionPath.
core/nodejs-helper.d.ts Type declaration for extensionPath.
.github/workflows/node-tests.yaml CI job to build the extension and run Node integration tests on ubuntu/macOS.
core/nodejs-install-helper.js Removed obsolete prebuild/downloader install helper script.
core/pnpm-lock.yaml Removed obsolete lockfile for the deleted pnpm-based Node setup.
Files not reviewed (1)
  • core/pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// Prefer build/ (dev) over dist/ (packaged).
const buildPath = join(root, "build", "crsqlite");
const distPath = join(root, "dist", "crsqlite");
const extensionPath = existsSync(buildPath + ".so") || existsSync(buildPath + ".dylib")

Copilot AI Apr 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extensionPath selection only checks for build/crsqlite.so and build/crsqlite.dylib. On Windows builds, CMake will typically produce build/crsqlite.dll, so this logic will incorrectly fall back to dist/ (and may fail to load if dist/ isn’t present). Include a .dll existence check (and/or prefer checking for any of the platform suffixes in both build/ and dist/).

Suggested change
const extensionPath = existsSync(buildPath + ".so") || existsSync(buildPath + ".dylib")
const hasExtensionBinary = (basePath) =>
[".so", ".dylib", ".dll"].some((suffix) => existsSync(basePath + suffix));
const extensionPath = hasExtensionBinary(buildPath)

Copilot uses AI. Check for mistakes.
Comment on lines +142 to +151
// Get changes from db2 and apply to db1
const changes2 = db2.prepare("SELECT * FROM crsql_changes WHERE db_version > 0").all();
const insertStmt1 = db1.prepare(
"INSERT INTO crsql_changes ([table], pk, cid, val, col_version, db_version, site_id, cl, seq) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
for (const c of changes2) {
// Only apply changes from db2's site
const db2SiteId = db2.prepare("SELECT crsql_site_id() AS sid").get().sid;
const changeSiteId = c.site_id;
// site_id comparison: apply non-local changes

Copilot AI Apr 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sync-back loop computes db2SiteId/changeSiteId but never uses them, and it re-inserts all rows from db2.crsql_changes (including changes that were just imported from db1). That means the test isn’t actually exercising the intended “only send non-local changes” behavior and does extra work. Filter the SELECT by site_id IS NOT (SELECT crsql_site_id() FROM db1) (like core/src/crsqlite.test.c’s syncLeftToRight) and/or filter to only db2-local changes before inserting into db1.

Suggested change
// Get changes from db2 and apply to db1
const changes2 = db2.prepare("SELECT * FROM crsql_changes WHERE db_version > 0").all();
const insertStmt1 = db1.prepare(
"INSERT INTO crsql_changes ([table], pk, cid, val, col_version, db_version, site_id, cl, seq) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
for (const c of changes2) {
// Only apply changes from db2's site
const db2SiteId = db2.prepare("SELECT crsql_site_id() AS sid").get().sid;
const changeSiteId = c.site_id;
// site_id comparison: apply non-local changes
// Get only db2-local changes and apply to db1
const db2SiteId = db2.prepare("SELECT crsql_site_id() AS sid").get().sid;
const changes2 = db2
.prepare("SELECT * FROM crsql_changes WHERE db_version > 0 AND site_id = ?")
.all(db2SiteId);
const insertStmt1 = db1.prepare(
"INSERT INTO crsql_changes ([table], pk, cid, val, col_version, db_version, site_id, cl, seq) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
for (const c of changes2) {

Copilot uses AI. Check for mistakes.

- uses: actions/setup-node@v4
with:
node-version: "22"

Copilot AI Apr 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow pins Node to major version "22", but these tests require Node >= 22.5 for node:sqlite. To avoid CI picking an older 22.x on some runners/caches, set an explicit minimum (e.g. 22.5.0) or a constraint that guarantees >=22.5.

Suggested change
node-version: "22"
node-version: "22.5.0"

Copilot uses AI. Check for mistakes.
@sinkingsugar sinkingsugar merged commit 13dd58a into pure-c-port Apr 12, 2026
12 checks passed
@sinkingsugar sinkingsugar deleted the claude/node-integration-options-Is824 branch April 12, 2026 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants